// config.cpp

#include <../pugixml/pugixml.hpp>
#include <../pugixml/pugiconfig.hpp>
#include <../SerialPort/nullserialport.h>
#include <../SerialPort/rs232.h>
#include <../SerialPort/udptunnel.h>
#include <../SerialPort/tcptunnel.h>
#include <config.h>

using namespace pugi;


Config::Config(const std::string &filename)
	: initialized_(false)
	, doc_(new xml_document())
	, filename_(filename)
{
}

Config::~Config()
{
	delete doc_;
}


bool Config::init(void)
{
	if (!initialized_)
		initialized_ = doc_->load_file(filename_.c_str());

	return initialized_;
}


SerialPort *Config::createInterface(const std::string &devname)
{
	if (!init())
		return new NullSerialPort();

	xml_node node = doc_->child("config").child(devname.c_str());
	std::string name(node.attribute("iface").value());

	for (xml_node iface = node.child("iface"); !iface.empty(); iface = iface.next_sibling())
	{
		if (name != iface.attribute("name").value())
			continue;

		std::string type(iface.attribute("type").value());
		
		if (type == "serial")
		{
			return new Rs232(
				iface.attribute("port").value(), iface.attribute("baudrate").as_int(),
				100);	// timeout
		}
		else if (type == "udp")
		{
			return new UdpTunnel(
				iface.attribute("self").value(), iface.attribute("port-in").as_int(),
				iface.attribute("addr").value(), iface.attribute("port-out").as_int());
		}
		else if (type == "tcp")
		{
			return new TcpTunnel(
				iface.attribute("addr").value(), iface.attribute("port").as_int(), 
				iface.attribute("handshake").value(), TcpTunnel::CLIENT);
		}
		else if (type == "tcpserver")
		{
			return new TcpTunnel(
				iface.attribute("addr").value(), iface.attribute("port").as_int(), 
				iface.attribute("handshake").value(), TcpTunnel::SERVER);
		}
	}

	return new NullSerialPort();
}


std::string Config::getWatchWindowName()
{
	if (!init())
		return "";

	return doc_->child("config").child("watchwindow").attribute("name").value();
}


std::map<std::string, float> Config::getNoiseMap()
{
	std::map<std::string, float> noiseMap;

	if (init())
	{
		for (xml_node node = doc_->child("config").child("noise").child("channel"); !node.empty(); node = node.next_sibling())
			noiseMap[node.attribute("name").value()] = node.attribute("value").as_float();
	}

	return noiseMap;
}


int Config::getWatchTimeout(void)
{
	if (!init())
		return 3000;

	return doc_->child("config").child("watchwindow").attribute("timeout").as_int() * 1000;
}
